#include "minet_socket.h"
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>

#define BUFSIZE 1024
#define FILENAMESIZE 100

int handle_connection(int sock);

int main(int argc, char * argv[]) {
    int server_port = -1;
    int rc          =  0;
    int sock        = -1;
    int acceptor_socket = -1;
    struct sockaddr_in * saddr;

    /* parse command line args */
    if (argc != 3) {
		fprintf(stderr, "usage: http_server1 k|u port\n");
		exit(-1);
    }

    server_port = atoi(argv[2]);

    if (server_port < 1500) {
		fprintf(stderr, "INVALID PORT NUMBER: %d; can't be < 1500\n", server_port);
		exit(-1);
    }

    /* initialize minet */
    if (toupper(*(argv[1])) == 'K'){
        minet_init(MINET_KERNEL);
    } else if (toupper(*(argv[1])) == 'U'){
        minet_init(MINET_USER);
    }else{
        fprintf(stderr, "First argument must be k or u\n");
    }
    
    /* initialize and make socket */
    if((acceptor_socket = minet_socket(SOCK_STREAM)) < 0){
        fprintf(stderr, "Failed to create minet_socket.\n");
        exit(-1);
    }

    /* set server address*/
    saddr = (sockaddr_in*)malloc(sizeof(sockaddr_in));
    memset(saddr, 0, sizeof(sockaddr_in));
    saddr->sin_family = AF_INET;
    saddr->sin_port = htons(server_port);
    saddr->sin_addr.s_addr = INADDR_ANY;

    /* bind listening socket */
    if((minet_bind(acceptor_socket, saddr)) < 0){
        fprintf(stderr, "Failed on minet_bind.\n");
        exit(-1);
    }

    /* start listening */
    if((minet_listen(acceptor_socket, 32)) < 0){
        fprintf(stderr, "Failed on minet_listen.\n");
        exit(-1);
    }

	/* initialize connection state */
	fd_set openfds;
	fd_set readfds;
	FD_ZERO(&readfds);
	FD_ZERO(&openfds);

	/* add acceptor_socket to initial state */
	FD_SET(acceptor_socket, &openfds);


    printf("acceptor is %d\n", acceptor_socket);
	while(1) {
		
		/* reset read list */
		readfds = openfds;
		
		/* block until one or more sockets can be read */
		minet_select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
		
		/* check all sockets */
		for(int i=0; i<FD_SETSIZE; i = i + 1) {
		
            printf("i = %d\n", i);
			/* socket was marked by select */			
			if(FD_ISSET(i,&readfds) && FD_ISSET(i,&openfds)) {
				
				/* add new connection */
				if(i == acceptor_socket) {
					sock = minet_accept(acceptor_socket, NULL);
					FD_SET(sock, &openfds);
				}
			
				/* service existing connection */
				else {
					rc = handle_connection(i);
					FD_CLR(i, &openfds);
				}

			}
		}
    }
}

int handle_connection(int sock) {
    bool ok = false;
    char * buffer = (char *)malloc(BUFSIZE);
    char * filename = (char *)malloc(FILENAMESIZE);

    char * ok_response_f = "HTTP/1.0 200 OK\r\n"    \
    "Content-type: text/plain\r\n"                  \
    "Content-length: %d \r\n\r\n";

    char * notok_response = "HTTP/1.0 404 FILE NOT FOUND\r\n"   \
    "Content-type: text/html\r\n\r\n"                           \
    "<html><body bgColor=black text=white>\n"                   \
    "<h2>404 FILE NOT FOUND</h2>\n"                             \
    "</body></html>\n";

    /* first read loop -- get request and headers */
    memset(buffer, 0, BUFSIZE);
    memset(filename, 0, FILENAMESIZE);
    if ((minet_read(sock, buffer, BUFSIZE-1)) <= 0) {
        fprintf(stderr, "Failed on minet_read.\n");
        minet_close(sock);
        exit(-1);
    }

    /* parse request to get file name */
    /* Assumption: this is a GET request and filename contains no spaces */
    int filenamelength = 0;
    for(int i=4; i<strlen(buffer); i++) {
        if(buffer[i] == ' ') {
            break;
        }
        filenamelength++;
    }
    strncpy(filename, &buffer[4], filenamelength);

	/* check for '/' at the beginning of filename */
    if(filename[0] == '/') {
        memmove(filename, filename+1, strlen(filename));
    }

    /* try opening the file */
    FILE * req_file = NULL;
    req_file = fopen(filename,"r");
    if(req_file == NULL)
        ok = false;
    else
        ok = true;

    /* send response */
    if (ok) {
        /* send headers */
        if(minet_write(sock, ok_response_f, strlen(ok_response_f)) <= 0) {
            fprintf(stderr, "Failed on minet_write ok_response.\n");
            exit(-1);
        }
        /* send file */
        memset(buffer, 0, BUFSIZE);
        fgets(buffer, BUFSIZE, req_file);
        while(!feof(req_file)) {
            minet_write(sock, buffer, strlen(buffer));
            fgets(buffer, BUFSIZE, req_file);
        }
    } else {
        // send error response
        if(minet_write(sock, notok_response, strlen(ok_response_f)) <= 0) {
            fprintf(stderr, "Failed on minet_write notok_response.\n");
            exit(-1);
        }
    }

	/* close socket and free space */
    minet_close(sock);
    free(buffer);
    free(filename);

    if (ok) {
        return 0;
    } else {
        return -1;
    }
}

